package com.jzo2o.health.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.health.mapper.ReservationSettingMapper;
import com.jzo2o.health.model.domain.ReservationSetting;
import com.jzo2o.health.model.dto.request.ReservationSettingUpsertReqDTO;
import com.jzo2o.health.model.dto.response.ReservationDateResDTO;
import com.jzo2o.health.model.dto.response.ReservationSettingResDTO;
import com.jzo2o.health.service.IReservationSettingService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2023-11-01
 */
@Service
public class ReservationSettingServiceImpl extends ServiceImpl<ReservationSettingMapper, ReservationSetting> implements IReservationSettingService {
    @Resource
    private ReservationSettingMapper reservationSettingMapper;

    /**
     * 新增预约设置
     *
     * @param list 预约设置
     */
    @Override
    public void add(List<ReservationSetting> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }

        //根据日期批量查询预约设置
        List<LocalDate> orderDateList = list.stream().map(ReservationSetting::getOrderDate).collect(Collectors.toList());
        Map<LocalDate, Integer> map = batchQueryByOrderDate(orderDateList);

        for (ReservationSetting reservationSetting : list) {
            //当前及过去日期跳过更新
            if (LocalDateTime.now().isAfter(reservationSetting.getOrderDate().atStartOfDay())) {
                continue;
            }

            //根据日期查询是否已经进行了预约设置
            Integer reservations = map.get(reservationSetting.getOrderDate());
            if (ObjectUtil.isNotEmpty(reservations)) {
                //如果已经进行了设置需要执行更新
                if (reservationSetting.getNumber() < reservations) {
                    throw new CommonException("可预约人数需大于/等于已预约人数");
                }
                editNumberByOrderDate(reservationSetting);
            } else {
                //如果没有进行设置执行插入操作
                baseMapper.insert(reservationSetting);
            }
        }
    }

    /**
     * 根据日期批量查询预约设置
     *
     * @param orderDateList 日期列表
     * @return 预约设置
     */
    private Map<LocalDate, Integer> batchQueryByOrderDate(List<LocalDate> orderDateList) {
        LambdaQueryWrapper<ReservationSetting> queryWrapper = Wrappers.<ReservationSetting>lambdaQuery().in(ReservationSetting::getOrderDate, orderDateList);
        List<ReservationSetting> reservationSettingList = baseMapper.selectList(queryWrapper);
        if (CollUtil.isEmpty(reservationSettingList)) {
            return new HashMap<>();
        }

        return reservationSettingList.stream().collect(Collectors.toMap(ReservationSetting::getOrderDate, ReservationSetting::getReservations));
    }

    /**
     * 按月查询预约设置
     *
     * @param orderDate 月份，格式：2019-03
     * @return 预约设置
     */
    @Override
    public List<ReservationSettingResDTO> getReservationSettingByMonth(String orderDate) {
        //1.获取指定月份日期起止时间
        LocalDate minTime = LocalDateTimeUtil.parseDate(orderDate, DatePattern.NORM_MONTH_PATTERN);
        LocalDate maxTime = minTime.plusMonths(1).minusDays(1);

        //2.查询指定月份的预约配置
        LambdaQueryWrapper<ReservationSetting> queryWrapper = Wrappers.<ReservationSetting>lambdaQuery().between(ReservationSetting::getOrderDate, minTime, maxTime);
        List<ReservationSetting> reservationSettingList = baseMapper.selectList(queryWrapper);

        List<ReservationSettingResDTO> list = new ArrayList<>();
        if (CollUtil.isEmpty(reservationSettingList)) {
            return list;
        }

        //3.如果预约配置不为空，提取预约配置记录
        list = reservationSettingList.stream().map(r ->
                        ReservationSettingResDTO.builder()
                                .date(r.getOrderDate().toString())
                                .number(r.getNumber())
                                .reservations(r.getReservations())
                                .build())
                .collect(Collectors.toList());
        return list;
    }

    /**
     * 根据日期编辑预约数量
     *
     * @param reservationSettingUpsertReqDTO 预约设置编辑请求
     */
    @Override
    public void editNumberByDate(ReservationSettingUpsertReqDTO reservationSettingUpsertReqDTO) {
        //1.根据日期查询出预约设置
        LocalDate orderDate = reservationSettingUpsertReqDTO.getOrderDate();
        if (LocalDateTime.now().isAfter(orderDate.atStartOfDay())) {
            throw new CommonException("当前及过去日期不可更改");
        }
        ReservationSetting dbReservationSetting = queryByOrderDate(orderDate);

        ReservationSetting reservationSetting = BeanUtil.toBean(reservationSettingUpsertReqDTO, ReservationSetting.class);
        if (ObjectUtil.isNotEmpty(dbReservationSetting)) {
            //2.如果已经进行了设置需要执行更新
            Integer reservations = dbReservationSetting.getReservations();
            reservations = Optional.ofNullable(reservations).orElse(0);
            if (reservationSettingUpsertReqDTO.getNumber() < reservations) {
                throw new CommonException("可预约人数需大于/等于已预约人数");
            }
            editNumberByOrderDate(reservationSetting);
        } else {
            //3.没有进行设置，执行插入操作
            baseMapper.insert(reservationSetting);
        }
    }

    /**
     * 根据日期更新预约数量
     *
     * @param reservationSetting 预约设置
     */
    private void editNumberByOrderDate(ReservationSetting reservationSetting) {
        LambdaUpdateWrapper<ReservationSetting> updateWrapper = Wrappers.<ReservationSetting>lambdaUpdate()
                .eq(ReservationSetting::getOrderDate, reservationSetting.getOrderDate())
                .set(ObjectUtil.isNotEmpty(reservationSetting.getNumber()), ReservationSetting::getNumber, reservationSetting.getNumber());
        super.update(updateWrapper);
    }

    /**
     * 根据日期查询预约设置
     *
     * @param orderDate 日期
     * @return 预约设置
     */
    @Override
    public ReservationSetting queryByOrderDate(LocalDate orderDate) {
        LambdaQueryWrapper<ReservationSetting> queryWrapper = Wrappers.<ReservationSetting>lambdaQuery().eq(ReservationSetting::getOrderDate, orderDate);
        return baseMapper.selectOne(queryWrapper);
    }

    /**
     * 按月查询可预约日期
     *
     * @param month 月份，格式：yyyy-MM
     * @return 可预约日期
     */
    @Override
    public ReservationDateResDTO getReservationDateByMonth(String month) {
        //1.获取起止日期
        LocalDate minTime = LocalDateTimeUtil.parseDate(month, DatePattern.NORM_MONTH_PATTERN);
        LocalDate maxTime = minTime.plusMonths(1).minusDays(1);

        //2.查询指定月份预约设置信息
        LambdaQueryWrapper<ReservationSetting> queryWrapper = Wrappers.<ReservationSetting>lambdaQuery().between(ReservationSetting::getOrderDate, minTime, maxTime);
        List<ReservationSetting> reservationSettingList = baseMapper.selectList(queryWrapper);

        if (CollUtil.isEmpty(reservationSettingList)) {
            return new ReservationDateResDTO(Collections.emptyList());
        }

        //3.如果预约设置不为空，筛选出 预约上限>已预约人数 的记录
        List<String> list = reservationSettingList.stream()
                .filter(r -> r.getNumber() > r.getReservations())
                .map(r -> r.getOrderDate().toString())
                .collect(Collectors.toList());
        return new ReservationDateResDTO(list);
    }

    /**
     * 更新预约人数，自增1
     *
     * @param id 预约设置id
     * @return 更新结果
     */
    @Override
    public Integer updateReservations(Integer id) {
        return reservationSettingMapper.updateReservations(id);
    }
}
